/*
 * Copyright (c) 2011-2013, Peter Abeles. All Rights Reserved.
 *
 * This file is part of BoofCV (http://boofcv.org).
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package boofcv.alg.misc;

import boofcv.struct.image.*;

/**
 * Computes statistical properties of pixels inside an image.
 *
 * <p>DO NOT MODIFY: Generated by {@link boofcv.alg.misc.GenerateImageStatistics}</p>.
 *
 * @author Peter Abeles
 */
public class ImageStatistics {

	/**
	 * Returns the minimum element value.
	 * 
	 * @param input Input image. Not modified.
	 * @return Minimum pixel value.
	 */
	public static int min( ImageUInt8 input ) {

		int min = input.get(0,0);

		for( int y = 0; y < input.height; y++ ) {
			int index = input.startIndex + y*input.stride;
			int end = index + input.width;

			for( ; index < end; index++ ) {
				int v = input.data[index] & 0xFF;
				if( v < min )
					min = v;
			}
		}
		return min;
	}

	/**
	 * Returns the maximum element value.
	 * 
	 * @param input Input image. Not modified.
	 * @return Maximum pixel value.
	 */
	public static int max( ImageUInt8 input ) {

		int max = input.get(0,0);

		for( int y = 0; y < input.height; y++ ) {
			int index = input.startIndex + y*input.stride;
			int end = index + input.width;

			for( ; index < end; index++ ) {
				int v = input.data[index] & 0xFF;
				if( v > max )
					max = v;
			}
		}
		return max;
	}

	/**
	 * Returns the absolute value of the element with the largest absolute value.
	 * 
	 * @param input Input image. Not modified.
	 * @return Largest pixel absolute value.
	 */
	public static int maxAbs( ImageUInt8 input ) {

		int max = 0;

		for( int y = 0; y < input.height; y++ ) {
			int index = input.startIndex + y*input.stride;
			int end = index + input.width;

			for( ; index < end; index++ ) {
				int v = input.data[index]& 0xFF;
				if( v > max )
					max = v;
			}
		}
		return max;
	}

	/**
	 * <p>
	 * Returns the sum of all the pixels in the image.
	 * </p>
	 * 
	 * @param img Input image. Not modified.
	 */
	public static int sum( ImageUInt8 img ) {

		final int h = img.getHeight();
		final int w = img.getWidth();

		int total = 0;
		
		for (int y = 0; y < h; y++) {
			int index = img.getStartIndex() + y * img.getStride();
			
			int indexEnd = index+w;
			// for(int x = 0; x < w; x++ ) {
			for (; index < indexEnd; index++ ) {
				total += img.data[index] & 0xFF;
			}
		}
		
		return total;
	}

	/**
	 * Returns the mean pixel intensity value.
	 * 
	 * @param img Input image.  Not modified.
	 * @return Mean pixel intensity value
	 */
	public static double mean( ImageUInt8 img ) {
		return sum(img)/(double)(img.width*img.height);
	}

	/**
	 * Computes the variance of pixel intensity values inside the image.
	 *
	 * @param img Input image. Not modified.
	 * @param mean Mean pixel intensity value.   
	 * @return Pixel variance   
	 */
	public static double variance( ImageUInt8 img , double mean ) {

		double variance = 0;

		for (int y = 0; y < img.height; y++) {
			int index = img.getStartIndex() + y * img.getStride();

			int indexEnd = index+img.width;
			// for(int x = 0; x < img.width; x++ ) {
			for (; index < indexEnd; index++ ) {
				double d = (img.data[index]& 0xFF) - mean; 
				variance += d*d;
			}
		}

		return variance/(img.width*img.height);
	}

	/**
	 * <p>Computes the mean squared error (MSE) between the two images.</p>
	 *
	 * @param imgA first image. Not modified.
	 * @param imgB second image. Not modified.
	 * @return error between the two images.
	 */
	public static double meanDiffSq(ImageUInt8 imgA, ImageUInt8 imgB ) {
		int total = 0;

		for (int y = 0; y < imgA.height; y++) {
			int indexA = imgA.getStartIndex() + y * imgA.getStride();
			int indexB = imgB.getStartIndex() + y * imgB.getStride();
			for (int x = 0; x < imgA.width; x++,indexA++,indexB++) {
				int difference = (imgA.data[indexA]& 0xFF)-(imgB.data[indexB]& 0xFF);
				total += difference*difference;
			}
		}

		return total / (double)(imgA.width*imgA.height);
	}

	/**
	 * <p>Computes the mean squared error (MSE) between the two images.</p>
	 *
	 * @param imgA first image. Not modified.
	 * @param imgB second image. Not modified.
	 * @return error between the two images.
	 */
	public static double meanDiffAbs(ImageUInt8 imgA, ImageUInt8 imgB ) {
		int total = 0;

		for (int y = 0; y < imgA.height; y++) {
			int indexA = imgA.getStartIndex() + y * imgA.getStride();
			int indexB = imgB.getStartIndex() + y * imgB.getStride();
			for (int x = 0; x < imgA.width; x++,indexA++,indexB++) {
				int difference = (imgA.data[indexA]& 0xFF)-(imgB.data[indexB]& 0xFF);
				total += Math.abs(difference);
			}
		}

		return total / (double)(imgA.width*imgA.height);
	}

	/**
	 * Computes the histogram of intensity values for the image.
	 * 
	 * @param input (input) Image.
	 * @param histogram (output) Storage for histogram. Number of elements must be equal to max value.
	 */
	public static void histogram( ImageUInt8 input , int histogram[] ) {
		for( int i = 0; i < histogram.length; i++ )
			histogram[i] = 0;
		
		for( int y = 0; y < input.height; y++ ) {
			int index = input.startIndex + y*input.stride;
			int end = index + input.width;

			for( ; index < end; index++ ) {
				histogram[input.data[index]& 0xFF]++;
			}
		}
	}

	/**
	 * Returns the minimum element value.
	 * 
	 * @param input Input image. Not modified.
	 * @return Minimum pixel value.
	 */
	public static int min( ImageSInt8 input ) {

		int min = input.get(0,0);

		for( int y = 0; y < input.height; y++ ) {
			int index = input.startIndex + y*input.stride;
			int end = index + input.width;

			for( ; index < end; index++ ) {
				int v = input.data[index] ;
				if( v < min )
					min = v;
			}
		}
		return min;
	}

	/**
	 * Returns the maximum element value.
	 * 
	 * @param input Input image. Not modified.
	 * @return Maximum pixel value.
	 */
	public static int max( ImageSInt8 input ) {

		int max = input.get(0,0);

		for( int y = 0; y < input.height; y++ ) {
			int index = input.startIndex + y*input.stride;
			int end = index + input.width;

			for( ; index < end; index++ ) {
				int v = input.data[index] ;
				if( v > max )
					max = v;
			}
		}
		return max;
	}

	/**
	 * Returns the absolute value of the element with the largest absolute value.
	 * 
	 * @param input Input image. Not modified.
	 * @return Largest pixel absolute value.
	 */
	public static int maxAbs( ImageSInt8 input ) {

		int max = 0;

		for( int y = 0; y < input.height; y++ ) {
			int index = input.startIndex + y*input.stride;
			int end = index + input.width;

			for( ; index < end; index++ ) {
				int v = Math.abs(input.data[index]);
				if( v > max )
					max = v;
			}
		}
		return max;
	}

	/**
	 * <p>
	 * Returns the sum of all the pixels in the image.
	 * </p>
	 * 
	 * @param img Input image. Not modified.
	 */
	public static int sum( ImageSInt8 img ) {

		final int h = img.getHeight();
		final int w = img.getWidth();

		int total = 0;
		
		for (int y = 0; y < h; y++) {
			int index = img.getStartIndex() + y * img.getStride();
			
			int indexEnd = index+w;
			// for(int x = 0; x < w; x++ ) {
			for (; index < indexEnd; index++ ) {
				total += img.data[index] ;
			}
		}
		
		return total;
	}

	/**
	 * Returns the mean pixel intensity value.
	 * 
	 * @param img Input image.  Not modified.
	 * @return Mean pixel intensity value
	 */
	public static double mean( ImageSInt8 img ) {
		return sum(img)/(double)(img.width*img.height);
	}

	/**
	 * Computes the variance of pixel intensity values inside the image.
	 *
	 * @param img Input image. Not modified.
	 * @param mean Mean pixel intensity value.   
	 * @return Pixel variance   
	 */
	public static double variance( ImageSInt8 img , double mean ) {

		double variance = 0;

		for (int y = 0; y < img.height; y++) {
			int index = img.getStartIndex() + y * img.getStride();

			int indexEnd = index+img.width;
			// for(int x = 0; x < img.width; x++ ) {
			for (; index < indexEnd; index++ ) {
				double d = (img.data[index]) - mean; 
				variance += d*d;
			}
		}

		return variance/(img.width*img.height);
	}

	/**
	 * <p>Computes the mean squared error (MSE) between the two images.</p>
	 *
	 * @param imgA first image. Not modified.
	 * @param imgB second image. Not modified.
	 * @return error between the two images.
	 */
	public static double meanDiffSq(ImageSInt8 imgA, ImageSInt8 imgB ) {
		int total = 0;

		for (int y = 0; y < imgA.height; y++) {
			int indexA = imgA.getStartIndex() + y * imgA.getStride();
			int indexB = imgB.getStartIndex() + y * imgB.getStride();
			for (int x = 0; x < imgA.width; x++,indexA++,indexB++) {
				int difference = (imgA.data[indexA])-(imgB.data[indexB]);
				total += difference*difference;
			}
		}

		return total / (double)(imgA.width*imgA.height);
	}

	/**
	 * <p>Computes the mean squared error (MSE) between the two images.</p>
	 *
	 * @param imgA first image. Not modified.
	 * @param imgB second image. Not modified.
	 * @return error between the two images.
	 */
	public static double meanDiffAbs(ImageSInt8 imgA, ImageSInt8 imgB ) {
		int total = 0;

		for (int y = 0; y < imgA.height; y++) {
			int indexA = imgA.getStartIndex() + y * imgA.getStride();
			int indexB = imgB.getStartIndex() + y * imgB.getStride();
			for (int x = 0; x < imgA.width; x++,indexA++,indexB++) {
				int difference = (imgA.data[indexA])-(imgB.data[indexB]);
				total += Math.abs(difference);
			}
		}

		return total / (double)(imgA.width*imgA.height);
	}

	/**
	 * Computes the histogram of intensity values for the image.
	 * 
	 * @param input (input) Image.
	 * @param minValue (input) Minimum possible intensity value   
	 * @param histogram (output) Storage for histogram. Number of elements must be equal to max value.
	 */
	public static void histogram( ImageSInt8 input , int minValue , int histogram[] ) {
		for( int i = 0; i < histogram.length; i++ )
			histogram[i] = 0;
		
		for( int y = 0; y < input.height; y++ ) {
			int index = input.startIndex + y*input.stride;
			int end = index + input.width;

			for( ; index < end; index++ ) {
				// floor value. just convert to int rounds towards zero
				histogram[input.data[index] - minValue ]++;
			}
		}
	}

	/**
	 * Returns the minimum element value.
	 * 
	 * @param input Input image. Not modified.
	 * @return Minimum pixel value.
	 */
	public static int min( ImageUInt16 input ) {

		int min = input.get(0,0);

		for( int y = 0; y < input.height; y++ ) {
			int index = input.startIndex + y*input.stride;
			int end = index + input.width;

			for( ; index < end; index++ ) {
				int v = input.data[index] & 0xFFFF;
				if( v < min )
					min = v;
			}
		}
		return min;
	}

	/**
	 * Returns the maximum element value.
	 * 
	 * @param input Input image. Not modified.
	 * @return Maximum pixel value.
	 */
	public static int max( ImageUInt16 input ) {

		int max = input.get(0,0);

		for( int y = 0; y < input.height; y++ ) {
			int index = input.startIndex + y*input.stride;
			int end = index + input.width;

			for( ; index < end; index++ ) {
				int v = input.data[index] & 0xFFFF;
				if( v > max )
					max = v;
			}
		}
		return max;
	}

	/**
	 * Returns the absolute value of the element with the largest absolute value.
	 * 
	 * @param input Input image. Not modified.
	 * @return Largest pixel absolute value.
	 */
	public static int maxAbs( ImageUInt16 input ) {

		int max = 0;

		for( int y = 0; y < input.height; y++ ) {
			int index = input.startIndex + y*input.stride;
			int end = index + input.width;

			for( ; index < end; index++ ) {
				int v = input.data[index]& 0xFFFF;
				if( v > max )
					max = v;
			}
		}
		return max;
	}

	/**
	 * <p>
	 * Returns the sum of all the pixels in the image.
	 * </p>
	 * 
	 * @param img Input image. Not modified.
	 */
	public static int sum( ImageUInt16 img ) {

		final int h = img.getHeight();
		final int w = img.getWidth();

		int total = 0;
		
		for (int y = 0; y < h; y++) {
			int index = img.getStartIndex() + y * img.getStride();
			
			int indexEnd = index+w;
			// for(int x = 0; x < w; x++ ) {
			for (; index < indexEnd; index++ ) {
				total += img.data[index] & 0xFFFF;
			}
		}
		
		return total;
	}

	/**
	 * Returns the mean pixel intensity value.
	 * 
	 * @param img Input image.  Not modified.
	 * @return Mean pixel intensity value
	 */
	public static double mean( ImageUInt16 img ) {
		return sum(img)/(double)(img.width*img.height);
	}

	/**
	 * Computes the variance of pixel intensity values inside the image.
	 *
	 * @param img Input image. Not modified.
	 * @param mean Mean pixel intensity value.   
	 * @return Pixel variance   
	 */
	public static double variance( ImageUInt16 img , double mean ) {

		double variance = 0;

		for (int y = 0; y < img.height; y++) {
			int index = img.getStartIndex() + y * img.getStride();

			int indexEnd = index+img.width;
			// for(int x = 0; x < img.width; x++ ) {
			for (; index < indexEnd; index++ ) {
				double d = (img.data[index]& 0xFFFF) - mean; 
				variance += d*d;
			}
		}

		return variance/(img.width*img.height);
	}

	/**
	 * <p>Computes the mean squared error (MSE) between the two images.</p>
	 *
	 * @param imgA first image. Not modified.
	 * @param imgB second image. Not modified.
	 * @return error between the two images.
	 */
	public static double meanDiffSq(ImageUInt16 imgA, ImageUInt16 imgB ) {
		int total = 0;

		for (int y = 0; y < imgA.height; y++) {
			int indexA = imgA.getStartIndex() + y * imgA.getStride();
			int indexB = imgB.getStartIndex() + y * imgB.getStride();
			for (int x = 0; x < imgA.width; x++,indexA++,indexB++) {
				int difference = (imgA.data[indexA]& 0xFFFF)-(imgB.data[indexB]& 0xFFFF);
				total += difference*difference;
			}
		}

		return total / (double)(imgA.width*imgA.height);
	}

	/**
	 * <p>Computes the mean squared error (MSE) between the two images.</p>
	 *
	 * @param imgA first image. Not modified.
	 * @param imgB second image. Not modified.
	 * @return error between the two images.
	 */
	public static double meanDiffAbs(ImageUInt16 imgA, ImageUInt16 imgB ) {
		int total = 0;

		for (int y = 0; y < imgA.height; y++) {
			int indexA = imgA.getStartIndex() + y * imgA.getStride();
			int indexB = imgB.getStartIndex() + y * imgB.getStride();
			for (int x = 0; x < imgA.width; x++,indexA++,indexB++) {
				int difference = (imgA.data[indexA]& 0xFFFF)-(imgB.data[indexB]& 0xFFFF);
				total += Math.abs(difference);
			}
		}

		return total / (double)(imgA.width*imgA.height);
	}

	/**
	 * Computes the histogram of intensity values for the image.
	 * 
	 * @param input (input) Image.
	 * @param histogram (output) Storage for histogram. Number of elements must be equal to max value.
	 */
	public static void histogram( ImageUInt16 input , int histogram[] ) {
		for( int i = 0; i < histogram.length; i++ )
			histogram[i] = 0;
		
		for( int y = 0; y < input.height; y++ ) {
			int index = input.startIndex + y*input.stride;
			int end = index + input.width;

			for( ; index < end; index++ ) {
				histogram[input.data[index]& 0xFFFF]++;
			}
		}
	}

	/**
	 * Returns the minimum element value.
	 * 
	 * @param input Input image. Not modified.
	 * @return Minimum pixel value.
	 */
	public static int min( ImageSInt16 input ) {

		int min = input.get(0,0);

		for( int y = 0; y < input.height; y++ ) {
			int index = input.startIndex + y*input.stride;
			int end = index + input.width;

			for( ; index < end; index++ ) {
				int v = input.data[index] ;
				if( v < min )
					min = v;
			}
		}
		return min;
	}

	/**
	 * Returns the maximum element value.
	 * 
	 * @param input Input image. Not modified.
	 * @return Maximum pixel value.
	 */
	public static int max( ImageSInt16 input ) {

		int max = input.get(0,0);

		for( int y = 0; y < input.height; y++ ) {
			int index = input.startIndex + y*input.stride;
			int end = index + input.width;

			for( ; index < end; index++ ) {
				int v = input.data[index] ;
				if( v > max )
					max = v;
			}
		}
		return max;
	}

	/**
	 * Returns the absolute value of the element with the largest absolute value.
	 * 
	 * @param input Input image. Not modified.
	 * @return Largest pixel absolute value.
	 */
	public static int maxAbs( ImageSInt16 input ) {

		int max = 0;

		for( int y = 0; y < input.height; y++ ) {
			int index = input.startIndex + y*input.stride;
			int end = index + input.width;

			for( ; index < end; index++ ) {
				int v = Math.abs(input.data[index]);
				if( v > max )
					max = v;
			}
		}
		return max;
	}

	/**
	 * <p>
	 * Returns the sum of all the pixels in the image.
	 * </p>
	 * 
	 * @param img Input image. Not modified.
	 */
	public static int sum( ImageSInt16 img ) {

		final int h = img.getHeight();
		final int w = img.getWidth();

		int total = 0;
		
		for (int y = 0; y < h; y++) {
			int index = img.getStartIndex() + y * img.getStride();
			
			int indexEnd = index+w;
			// for(int x = 0; x < w; x++ ) {
			for (; index < indexEnd; index++ ) {
				total += img.data[index] ;
			}
		}
		
		return total;
	}

	/**
	 * Returns the mean pixel intensity value.
	 * 
	 * @param img Input image.  Not modified.
	 * @return Mean pixel intensity value
	 */
	public static double mean( ImageSInt16 img ) {
		return sum(img)/(double)(img.width*img.height);
	}

	/**
	 * Computes the variance of pixel intensity values inside the image.
	 *
	 * @param img Input image. Not modified.
	 * @param mean Mean pixel intensity value.   
	 * @return Pixel variance   
	 */
	public static double variance( ImageSInt16 img , double mean ) {

		double variance = 0;

		for (int y = 0; y < img.height; y++) {
			int index = img.getStartIndex() + y * img.getStride();

			int indexEnd = index+img.width;
			// for(int x = 0; x < img.width; x++ ) {
			for (; index < indexEnd; index++ ) {
				double d = (img.data[index]) - mean; 
				variance += d*d;
			}
		}

		return variance/(img.width*img.height);
	}

	/**
	 * <p>Computes the mean squared error (MSE) between the two images.</p>
	 *
	 * @param imgA first image. Not modified.
	 * @param imgB second image. Not modified.
	 * @return error between the two images.
	 */
	public static double meanDiffSq(ImageSInt16 imgA, ImageSInt16 imgB ) {
		int total = 0;

		for (int y = 0; y < imgA.height; y++) {
			int indexA = imgA.getStartIndex() + y * imgA.getStride();
			int indexB = imgB.getStartIndex() + y * imgB.getStride();
			for (int x = 0; x < imgA.width; x++,indexA++,indexB++) {
				int difference = (imgA.data[indexA])-(imgB.data[indexB]);
				total += difference*difference;
			}
		}

		return total / (double)(imgA.width*imgA.height);
	}

	/**
	 * <p>Computes the mean squared error (MSE) between the two images.</p>
	 *
	 * @param imgA first image. Not modified.
	 * @param imgB second image. Not modified.
	 * @return error between the two images.
	 */
	public static double meanDiffAbs(ImageSInt16 imgA, ImageSInt16 imgB ) {
		int total = 0;

		for (int y = 0; y < imgA.height; y++) {
			int indexA = imgA.getStartIndex() + y * imgA.getStride();
			int indexB = imgB.getStartIndex() + y * imgB.getStride();
			for (int x = 0; x < imgA.width; x++,indexA++,indexB++) {
				int difference = (imgA.data[indexA])-(imgB.data[indexB]);
				total += Math.abs(difference);
			}
		}

		return total / (double)(imgA.width*imgA.height);
	}

	/**
	 * Computes the histogram of intensity values for the image.
	 * 
	 * @param input (input) Image.
	 * @param minValue (input) Minimum possible intensity value   
	 * @param histogram (output) Storage for histogram. Number of elements must be equal to max value.
	 */
	public static void histogram( ImageSInt16 input , int minValue , int histogram[] ) {
		for( int i = 0; i < histogram.length; i++ )
			histogram[i] = 0;
		
		for( int y = 0; y < input.height; y++ ) {
			int index = input.startIndex + y*input.stride;
			int end = index + input.width;

			for( ; index < end; index++ ) {
				// floor value. just convert to int rounds towards zero
				histogram[input.data[index] - minValue ]++;
			}
		}
	}

	/**
	 * Returns the minimum element value.
	 * 
	 * @param input Input image. Not modified.
	 * @return Minimum pixel value.
	 */
	public static int min( ImageSInt32 input ) {

		int min = input.get(0,0);

		for( int y = 0; y < input.height; y++ ) {
			int index = input.startIndex + y*input.stride;
			int end = index + input.width;

			for( ; index < end; index++ ) {
				int v = input.data[index] ;
				if( v < min )
					min = v;
			}
		}
		return min;
	}

	/**
	 * Returns the maximum element value.
	 * 
	 * @param input Input image. Not modified.
	 * @return Maximum pixel value.
	 */
	public static int max( ImageSInt32 input ) {

		int max = input.get(0,0);

		for( int y = 0; y < input.height; y++ ) {
			int index = input.startIndex + y*input.stride;
			int end = index + input.width;

			for( ; index < end; index++ ) {
				int v = input.data[index] ;
				if( v > max )
					max = v;
			}
		}
		return max;
	}

	/**
	 * Returns the absolute value of the element with the largest absolute value.
	 * 
	 * @param input Input image. Not modified.
	 * @return Largest pixel absolute value.
	 */
	public static int maxAbs( ImageSInt32 input ) {

		int max = 0;

		for( int y = 0; y < input.height; y++ ) {
			int index = input.startIndex + y*input.stride;
			int end = index + input.width;

			for( ; index < end; index++ ) {
				int v = Math.abs(input.data[index]);
				if( v > max )
					max = v;
			}
		}
		return max;
	}

	/**
	 * <p>
	 * Returns the sum of all the pixels in the image.
	 * </p>
	 * 
	 * @param img Input image. Not modified.
	 */
	public static int sum( ImageSInt32 img ) {

		final int h = img.getHeight();
		final int w = img.getWidth();

		int total = 0;
		
		for (int y = 0; y < h; y++) {
			int index = img.getStartIndex() + y * img.getStride();
			
			int indexEnd = index+w;
			// for(int x = 0; x < w; x++ ) {
			for (; index < indexEnd; index++ ) {
				total += img.data[index] ;
			}
		}
		
		return total;
	}

	/**
	 * Returns the mean pixel intensity value.
	 * 
	 * @param img Input image.  Not modified.
	 * @return Mean pixel intensity value
	 */
	public static double mean( ImageSInt32 img ) {
		return sum(img)/(double)(img.width*img.height);
	}

	/**
	 * Computes the variance of pixel intensity values inside the image.
	 *
	 * @param img Input image. Not modified.
	 * @param mean Mean pixel intensity value.   
	 * @return Pixel variance   
	 */
	public static double variance( ImageSInt32 img , double mean ) {

		double variance = 0;

		for (int y = 0; y < img.height; y++) {
			int index = img.getStartIndex() + y * img.getStride();

			int indexEnd = index+img.width;
			// for(int x = 0; x < img.width; x++ ) {
			for (; index < indexEnd; index++ ) {
				double d = (img.data[index]) - mean; 
				variance += d*d;
			}
		}

		return variance/(img.width*img.height);
	}

	/**
	 * <p>Computes the mean squared error (MSE) between the two images.</p>
	 *
	 * @param imgA first image. Not modified.
	 * @param imgB second image. Not modified.
	 * @return error between the two images.
	 */
	public static double meanDiffSq(ImageSInt32 imgA, ImageSInt32 imgB ) {
		long total = 0;

		for (int y = 0; y < imgA.height; y++) {
			int indexA = imgA.getStartIndex() + y * imgA.getStride();
			int indexB = imgB.getStartIndex() + y * imgB.getStride();
			for (int x = 0; x < imgA.width; x++,indexA++,indexB++) {
				int difference = (imgA.data[indexA])-(imgB.data[indexB]);
				total += difference*difference;
			}
		}

		return total / (double)(imgA.width*imgA.height);
	}

	/**
	 * <p>Computes the mean squared error (MSE) between the two images.</p>
	 *
	 * @param imgA first image. Not modified.
	 * @param imgB second image. Not modified.
	 * @return error between the two images.
	 */
	public static double meanDiffAbs(ImageSInt32 imgA, ImageSInt32 imgB ) {
		int total = 0;

		for (int y = 0; y < imgA.height; y++) {
			int indexA = imgA.getStartIndex() + y * imgA.getStride();
			int indexB = imgB.getStartIndex() + y * imgB.getStride();
			for (int x = 0; x < imgA.width; x++,indexA++,indexB++) {
				int difference = (imgA.data[indexA])-(imgB.data[indexB]);
				total += Math.abs(difference);
			}
		}

		return total / (double)(imgA.width*imgA.height);
	}

	/**
	 * Computes the histogram of intensity values for the image.
	 * 
	 * @param input (input) Image.
	 * @param minValue (input) Minimum possible intensity value   
	 * @param histogram (output) Storage for histogram. Number of elements must be equal to max value.
	 */
	public static void histogram( ImageSInt32 input , int minValue , int histogram[] ) {
		for( int i = 0; i < histogram.length; i++ )
			histogram[i] = 0;
		
		for( int y = 0; y < input.height; y++ ) {
			int index = input.startIndex + y*input.stride;
			int end = index + input.width;

			for( ; index < end; index++ ) {
				// floor value. just convert to int rounds towards zero
				histogram[input.data[index] - minValue ]++;
			}
		}
	}

	/**
	 * Returns the minimum element value.
	 * 
	 * @param input Input image. Not modified.
	 * @return Minimum pixel value.
	 */
	public static long min( ImageSInt64 input ) {

		long min = input.get(0,0);

		for( int y = 0; y < input.height; y++ ) {
			int index = input.startIndex + y*input.stride;
			int end = index + input.width;

			for( ; index < end; index++ ) {
				long v = input.data[index] ;
				if( v < min )
					min = v;
			}
		}
		return min;
	}

	/**
	 * Returns the maximum element value.
	 * 
	 * @param input Input image. Not modified.
	 * @return Maximum pixel value.
	 */
	public static long max( ImageSInt64 input ) {

		long max = input.get(0,0);

		for( int y = 0; y < input.height; y++ ) {
			int index = input.startIndex + y*input.stride;
			int end = index + input.width;

			for( ; index < end; index++ ) {
				long v = input.data[index] ;
				if( v > max )
					max = v;
			}
		}
		return max;
	}

	/**
	 * Returns the absolute value of the element with the largest absolute value.
	 * 
	 * @param input Input image. Not modified.
	 * @return Largest pixel absolute value.
	 */
	public static long maxAbs( ImageSInt64 input ) {

		long max = 0;

		for( int y = 0; y < input.height; y++ ) {
			int index = input.startIndex + y*input.stride;
			int end = index + input.width;

			for( ; index < end; index++ ) {
				long v = Math.abs(input.data[index]);
				if( v > max )
					max = v;
			}
		}
		return max;
	}

	/**
	 * <p>
	 * Returns the sum of all the pixels in the image.
	 * </p>
	 * 
	 * @param img Input image. Not modified.
	 */
	public static long sum( ImageSInt64 img ) {

		final int h = img.getHeight();
		final int w = img.getWidth();

		long total = 0;
		
		for (int y = 0; y < h; y++) {
			int index = img.getStartIndex() + y * img.getStride();
			
			int indexEnd = index+w;
			// for(int x = 0; x < w; x++ ) {
			for (; index < indexEnd; index++ ) {
				total += img.data[index] ;
			}
		}
		
		return total;
	}

	/**
	 * Returns the mean pixel intensity value.
	 * 
	 * @param img Input image.  Not modified.
	 * @return Mean pixel intensity value
	 */
	public static double mean( ImageSInt64 img ) {
		return sum(img)/(double)(img.width*img.height);
	}

	/**
	 * Computes the variance of pixel intensity values inside the image.
	 *
	 * @param img Input image. Not modified.
	 * @param mean Mean pixel intensity value.   
	 * @return Pixel variance   
	 */
	public static double variance( ImageSInt64 img , double mean ) {

		double variance = 0;

		for (int y = 0; y < img.height; y++) {
			int index = img.getStartIndex() + y * img.getStride();

			int indexEnd = index+img.width;
			// for(int x = 0; x < img.width; x++ ) {
			for (; index < indexEnd; index++ ) {
				double d = (img.data[index]) - mean; 
				variance += d*d;
			}
		}

		return variance/(img.width*img.height);
	}

	/**
	 * <p>Computes the mean squared error (MSE) between the two images.</p>
	 *
	 * @param imgA first image. Not modified.
	 * @param imgB second image. Not modified.
	 * @return error between the two images.
	 */
	public static double meanDiffSq(ImageSInt64 imgA, ImageSInt64 imgB ) {
		long total = 0;

		for (int y = 0; y < imgA.height; y++) {
			int indexA = imgA.getStartIndex() + y * imgA.getStride();
			int indexB = imgB.getStartIndex() + y * imgB.getStride();
			for (int x = 0; x < imgA.width; x++,indexA++,indexB++) {
				long difference = (imgA.data[indexA])-(imgB.data[indexB]);
				total += difference*difference;
			}
		}

		return total / (double)(imgA.width*imgA.height);
	}

	/**
	 * <p>Computes the mean squared error (MSE) between the two images.</p>
	 *
	 * @param imgA first image. Not modified.
	 * @param imgB second image. Not modified.
	 * @return error between the two images.
	 */
	public static double meanDiffAbs(ImageSInt64 imgA, ImageSInt64 imgB ) {
		long total = 0;

		for (int y = 0; y < imgA.height; y++) {
			int indexA = imgA.getStartIndex() + y * imgA.getStride();
			int indexB = imgB.getStartIndex() + y * imgB.getStride();
			for (int x = 0; x < imgA.width; x++,indexA++,indexB++) {
				long difference = (imgA.data[indexA])-(imgB.data[indexB]);
				total += Math.abs(difference);
			}
		}

		return total / (double)(imgA.width*imgA.height);
	}

	/**
	 * Computes the histogram of intensity values for the image.
	 * 
	 * @param input (input) Image.
	 * @param minValue (input) Minimum possible intensity value   
	 * @param histogram (output) Storage for histogram. Number of elements must be equal to max value.
	 */
	public static void histogram( ImageSInt64 input , int minValue , int histogram[] ) {
		for( int i = 0; i < histogram.length; i++ )
			histogram[i] = 0;
		
		for( int y = 0; y < input.height; y++ ) {
			int index = input.startIndex + y*input.stride;
			int end = index + input.width;

			for( ; index < end; index++ ) {
				// floor value. just convert to int rounds towards zero
				histogram[(int)input.data[index] - minValue]++;
			}
		}
	}

	/**
	 * Returns the minimum element value.
	 * 
	 * @param input Input image. Not modified.
	 * @return Minimum pixel value.
	 */
	public static float min( ImageFloat32 input ) {

		float min = input.get(0,0);

		for( int y = 0; y < input.height; y++ ) {
			int index = input.startIndex + y*input.stride;
			int end = index + input.width;

			for( ; index < end; index++ ) {
				float v = input.data[index] ;
				if( v < min )
					min = v;
			}
		}
		return min;
	}

	/**
	 * Returns the maximum element value.
	 * 
	 * @param input Input image. Not modified.
	 * @return Maximum pixel value.
	 */
	public static float max( ImageFloat32 input ) {

		float max = input.get(0,0);

		for( int y = 0; y < input.height; y++ ) {
			int index = input.startIndex + y*input.stride;
			int end = index + input.width;

			for( ; index < end; index++ ) {
				float v = input.data[index] ;
				if( v > max )
					max = v;
			}
		}
		return max;
	}

	/**
	 * Returns the absolute value of the element with the largest absolute value.
	 * 
	 * @param input Input image. Not modified.
	 * @return Largest pixel absolute value.
	 */
	public static float maxAbs( ImageFloat32 input ) {

		float max = 0;

		for( int y = 0; y < input.height; y++ ) {
			int index = input.startIndex + y*input.stride;
			int end = index + input.width;

			for( ; index < end; index++ ) {
				float v = Math.abs(input.data[index]);
				if( v > max )
					max = v;
			}
		}
		return max;
	}

	/**
	 * <p>
	 * Returns the sum of all the pixels in the image.
	 * </p>
	 * 
	 * @param img Input image. Not modified.
	 */
	public static float sum( ImageFloat32 img ) {

		final int h = img.getHeight();
		final int w = img.getWidth();

		float total = 0;
		
		for (int y = 0; y < h; y++) {
			int index = img.getStartIndex() + y * img.getStride();
			
			int indexEnd = index+w;
			// for(int x = 0; x < w; x++ ) {
			for (; index < indexEnd; index++ ) {
				total += img.data[index] ;
			}
		}
		
		return total;
	}

	/**
	 * Returns the mean pixel intensity value.
	 * 
	 * @param img Input image.  Not modified.
	 * @return Mean pixel intensity value
	 */
	public static double mean( ImageFloat32 img ) {
		return sum(img)/(double)(img.width*img.height);
	}

	/**
	 * Computes the variance of pixel intensity values inside the image.
	 *
	 * @param img Input image. Not modified.
	 * @param mean Mean pixel intensity value.   
	 * @return Pixel variance   
	 */
	public static double variance( ImageFloat32 img , double mean ) {

		double variance = 0;

		for (int y = 0; y < img.height; y++) {
			int index = img.getStartIndex() + y * img.getStride();

			int indexEnd = index+img.width;
			// for(int x = 0; x < img.width; x++ ) {
			for (; index < indexEnd; index++ ) {
				double d = (img.data[index]) - mean; 
				variance += d*d;
			}
		}

		return variance/(img.width*img.height);
	}

	/**
	 * <p>Computes the mean squared error (MSE) between the two images.</p>
	 *
	 * @param imgA first image. Not modified.
	 * @param imgB second image. Not modified.
	 * @return error between the two images.
	 */
	public static double meanDiffSq(ImageFloat32 imgA, ImageFloat32 imgB ) {
		double total = 0;

		for (int y = 0; y < imgA.height; y++) {
			int indexA = imgA.getStartIndex() + y * imgA.getStride();
			int indexB = imgB.getStartIndex() + y * imgB.getStride();
			for (int x = 0; x < imgA.width; x++,indexA++,indexB++) {
				float difference = (imgA.data[indexA])-(imgB.data[indexB]);
				total += difference*difference;
			}
		}

		return total / (double)(imgA.width*imgA.height);
	}

	/**
	 * <p>Computes the mean squared error (MSE) between the two images.</p>
	 *
	 * @param imgA first image. Not modified.
	 * @param imgB second image. Not modified.
	 * @return error between the two images.
	 */
	public static double meanDiffAbs(ImageFloat32 imgA, ImageFloat32 imgB ) {
		float total = 0;

		for (int y = 0; y < imgA.height; y++) {
			int indexA = imgA.getStartIndex() + y * imgA.getStride();
			int indexB = imgB.getStartIndex() + y * imgB.getStride();
			for (int x = 0; x < imgA.width; x++,indexA++,indexB++) {
				float difference = (imgA.data[indexA])-(imgB.data[indexB]);
				total += Math.abs(difference);
			}
		}

		return total / (double)(imgA.width*imgA.height);
	}

	/**
	 * Computes the histogram of intensity values for the image.
	 * 
	 * @param input (input) Image.
	 * @param minValue (input) Minimum possible intensity value   
	 * @param histogram (output) Storage for histogram. Number of elements must be equal to max value.
	 */
	public static void histogram( ImageFloat32 input , int minValue , int histogram[] ) {
		for( int i = 0; i < histogram.length; i++ )
			histogram[i] = 0;
		
		for( int y = 0; y < input.height; y++ ) {
			int index = input.startIndex + y*input.stride;
			int end = index + input.width;

			for( ; index < end; index++ ) {
				// floor value. just convert to int rounds towards zero
				histogram[(int)input.data[index] - minValue ]++;
			}
		}
	}

	/**
	 * Returns the minimum element value.
	 * 
	 * @param input Input image. Not modified.
	 * @return Minimum pixel value.
	 */
	public static double min( ImageFloat64 input ) {

		double min = input.get(0,0);

		for( int y = 0; y < input.height; y++ ) {
			int index = input.startIndex + y*input.stride;
			int end = index + input.width;

			for( ; index < end; index++ ) {
				double v = input.data[index] ;
				if( v < min )
					min = v;
			}
		}
		return min;
	}

	/**
	 * Returns the maximum element value.
	 * 
	 * @param input Input image. Not modified.
	 * @return Maximum pixel value.
	 */
	public static double max( ImageFloat64 input ) {

		double max = input.get(0,0);

		for( int y = 0; y < input.height; y++ ) {
			int index = input.startIndex + y*input.stride;
			int end = index + input.width;

			for( ; index < end; index++ ) {
				double v = input.data[index] ;
				if( v > max )
					max = v;
			}
		}
		return max;
	}

	/**
	 * Returns the absolute value of the element with the largest absolute value.
	 * 
	 * @param input Input image. Not modified.
	 * @return Largest pixel absolute value.
	 */
	public static double maxAbs( ImageFloat64 input ) {

		double max = 0;

		for( int y = 0; y < input.height; y++ ) {
			int index = input.startIndex + y*input.stride;
			int end = index + input.width;

			for( ; index < end; index++ ) {
				double v = Math.abs(input.data[index]);
				if( v > max )
					max = v;
			}
		}
		return max;
	}

	/**
	 * <p>
	 * Returns the sum of all the pixels in the image.
	 * </p>
	 * 
	 * @param img Input image. Not modified.
	 */
	public static double sum( ImageFloat64 img ) {

		final int h = img.getHeight();
		final int w = img.getWidth();

		double total = 0;
		
		for (int y = 0; y < h; y++) {
			int index = img.getStartIndex() + y * img.getStride();
			
			int indexEnd = index+w;
			// for(int x = 0; x < w; x++ ) {
			for (; index < indexEnd; index++ ) {
				total += img.data[index] ;
			}
		}
		
		return total;
	}

	/**
	 * Returns the mean pixel intensity value.
	 * 
	 * @param img Input image.  Not modified.
	 * @return Mean pixel intensity value
	 */
	public static double mean( ImageFloat64 img ) {
		return sum(img)/(double)(img.width*img.height);
	}

	/**
	 * Computes the variance of pixel intensity values inside the image.
	 *
	 * @param img Input image. Not modified.
	 * @param mean Mean pixel intensity value.   
	 * @return Pixel variance   
	 */
	public static double variance( ImageFloat64 img , double mean ) {

		double variance = 0;

		for (int y = 0; y < img.height; y++) {
			int index = img.getStartIndex() + y * img.getStride();

			int indexEnd = index+img.width;
			// for(int x = 0; x < img.width; x++ ) {
			for (; index < indexEnd; index++ ) {
				double d = (img.data[index]) - mean; 
				variance += d*d;
			}
		}

		return variance/(img.width*img.height);
	}

	/**
	 * <p>Computes the mean squared error (MSE) between the two images.</p>
	 *
	 * @param imgA first image. Not modified.
	 * @param imgB second image. Not modified.
	 * @return error between the two images.
	 */
	public static double meanDiffSq(ImageFloat64 imgA, ImageFloat64 imgB ) {
		double total = 0;

		for (int y = 0; y < imgA.height; y++) {
			int indexA = imgA.getStartIndex() + y * imgA.getStride();
			int indexB = imgB.getStartIndex() + y * imgB.getStride();
			for (int x = 0; x < imgA.width; x++,indexA++,indexB++) {
				double difference = (imgA.data[indexA])-(imgB.data[indexB]);
				total += difference*difference;
			}
		}

		return total / (double)(imgA.width*imgA.height);
	}

	/**
	 * <p>Computes the mean squared error (MSE) between the two images.</p>
	 *
	 * @param imgA first image. Not modified.
	 * @param imgB second image. Not modified.
	 * @return error between the two images.
	 */
	public static double meanDiffAbs(ImageFloat64 imgA, ImageFloat64 imgB ) {
		double total = 0;

		for (int y = 0; y < imgA.height; y++) {
			int indexA = imgA.getStartIndex() + y * imgA.getStride();
			int indexB = imgB.getStartIndex() + y * imgB.getStride();
			for (int x = 0; x < imgA.width; x++,indexA++,indexB++) {
				double difference = (imgA.data[indexA])-(imgB.data[indexB]);
				total += Math.abs(difference);
			}
		}

		return total / (double)(imgA.width*imgA.height);
	}

	/**
	 * Computes the histogram of intensity values for the image.
	 * 
	 * @param input (input) Image.
	 * @param minValue (input) Minimum possible intensity value   
	 * @param histogram (output) Storage for histogram. Number of elements must be equal to max value.
	 */
	public static void histogram( ImageFloat64 input , int minValue , int histogram[] ) {
		for( int i = 0; i < histogram.length; i++ )
			histogram[i] = 0;
		
		for( int y = 0; y < input.height; y++ ) {
			int index = input.startIndex + y*input.stride;
			int end = index + input.width;

			for( ; index < end; index++ ) {
				// floor value. just convert to int rounds towards zero
				histogram[(int)input.data[index] - minValue ]++;
			}
		}
	}

}
